const { exec } = require('child_process');
const fs = require('fs');
const path = require('path');
const dotenv = require('dotenv');

// Load environment variables
dotenv.config({ path: path.join(__dirname, '..', 'backend', '.env') });

// Backup directory
const BACKUP_DIR = path.join(__dirname, '..', 'backups');

// Ensure backup directory exists
if (!fs.existsSync(BACKUP_DIR)) {
  fs.mkdirSync(BACKUP_DIR, { recursive: true });
}

// Backup log file
const LOG_FILE = path.join(BACKUP_DIR, 'backup.log');

/**
 * Log message to file and console
 * @param {string} message - Message to log
 */
function logMessage(message) {
  const timestamp = new Date().toISOString();
  const logEntry = `[${timestamp}] ${message}\n`;
  
  console.log(message);
  
  // Append to log file
  fs.appendFileSync(LOG_FILE, logEntry);
}

/**
 * Create a database backup
 * @param {boolean} isScheduled - Whether this is a scheduled backup
 */
function createBackup(isScheduled = false) {
  const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
  const backupFileName = `financeapp_backup_${timestamp}.sql`;
  const backupPath = path.join(BACKUP_DIR, backupFileName);
  
  // PostgreSQL connection details from environment variables
  const host = process.env.DB_HOST || 'localhost';
  const port = process.env.DB_PORT || '5432';
  const database = process.env.DB_NAME || 'financeapp';
  const username = process.env.DB_USER || 'financeapp_admin';
  
  // Create backup command
  const backupCommand = `pg_dump -h ${host} -p ${port} -U ${username} -d ${database} -f "${backupPath}"`;
  
  logMessage(`Creating backup: ${backupFileName}${isScheduled ? ' (scheduled)' : ''}`);
  
  // Set environment variable for password
  const env = { ...process.env, PGPASSWORD: process.env.DB_PASSWORD };
  
  exec(backupCommand, { env }, (error, stdout, stderr) => {
    if (error) {
      logMessage(`Backup failed: ${error.message}`);
      return;
    }
    
    if (stderr) {
      logMessage(`Backup stderr: ${stderr}`);
      return;
    }
    
    // Get file size
    const stats = fs.statSync(backupPath);
    const fileSize = (stats.size / (1024 * 1024)).toFixed(2); // Size in MB
    
    logMessage(`Backup created successfully: ${backupPath} (${fileSize} MB)`);
    
    // Clean up old backups (keep only last 7 days)
    cleanupOldBackups();
  });
}

/**
 * Clean up old backups (keep only last 7 days)
 */
function cleanupOldBackups() {
  try {
    const backups = fs.readdirSync(BACKUP_DIR)
      .filter(file => file.startsWith('financeapp_backup_') && file.endsWith('.sql'))
      .map(file => {
        // Extract timestamp from filename
        const timestampStr = file.replace('financeapp_backup_', '').replace('.sql', '');
        const timestamp = new Date(timestampStr.replace(/-/g, ':'));
        return { file, timestamp };
      })
      .sort((a, b) => b.timestamp - a.timestamp); // Sort by timestamp (newest first)
    
    // Keep only last 7 days of backups
    const cutoffDate = new Date();
    cutoffDate.setDate(cutoffDate.getDate() - 7);
    
    let deletedCount = 0;
    for (const backup of backups) {
      if (backup.timestamp < cutoffDate) {
        const backupPath = path.join(BACKUP_DIR, backup.file);
        fs.unlinkSync(backupPath);
        logMessage(`Deleted old backup: ${backup.file}`);
        deletedCount++;
      }
    }
    
    if (deletedCount > 0) {
      logMessage(`Cleaned up ${deletedCount} old backups`);
    }
  } catch (error) {
    logMessage(`Error cleaning up old backups: ${error.message}`);
  }
}

/**
 * List available backups
 */
function listBackups() {
  try {
    if (!fs.existsSync(BACKUP_DIR)) {
      logMessage('No backups found');
      return;
    }
    
    const backups = fs.readdirSync(BACKUP_DIR)
      .filter(file => file.startsWith('financeapp_backup_') && file.endsWith('.sql'))
      .map(file => {
        const stats = fs.statSync(path.join(BACKUP_DIR, file));
        return {
          file,
          size: stats.size,
          modified: stats.mtime
        };
      })
      .sort((a, b) => b.modified - a.modified); // Sort by modification time (newest first)
    
    if (backups.length === 0) {
      logMessage('No backups found');
      return;
    }
    
    logMessage('Available backups:');
    backups.forEach(backup => {
      const sizeMB = (backup.size / (1024 * 1024)).toFixed(2);
      const dateStr = backup.modified.toISOString().split('T')[0];
      logMessage(`  ${backup.file} (${sizeMB} MB, ${dateStr})`);
    });
  } catch (error) {
    logMessage(`Error listing backups: ${error.message}`);
  }
}

/**
 * Validate backup integrity
 * @param {string} backupFile - Backup file to validate
 */
function validateBackup(backupFile) {
  const backupPath = path.join(BACKUP_DIR, backupFile);
  
  // Check if backup file exists
  if (!fs.existsSync(backupPath)) {
    logMessage(`Backup file not found: ${backupPath}`);
    return false;
  }
  
  try {
    // Check file size
    const stats = fs.statSync(backupPath);
    if (stats.size === 0) {
      logMessage(`Backup file is empty: ${backupFile}`);
      return false;
    }
    
    // Check if file contains expected content
    const content = fs.readFileSync(backupPath, 'utf8');
    if (!content.includes('PostgreSQL database dump')) {
      logMessage(`Backup file may be corrupted: ${backupFile}`);
      return false;
    }
    
    logMessage(`Backup file is valid: ${backupFile} (${(stats.size / (1024 * 1024)).toFixed(2)} MB)`);
    return true;
  } catch (error) {
    logMessage(`Error validating backup: ${error.message}`);
    return false;
  }
}

/**
 * Schedule daily backups
 */
function scheduleBackups() {
  logMessage('Backup scheduler started');
  
  // Run backup immediately
  createBackup(true);
  
  // Schedule daily backups at 2:00 AM
  setInterval(() => {
    const now = new Date();
    if (now.getHours() === 2 && now.getMinutes() === 0) {
      createBackup(true);
    }
  }, 60000); // Check every minute
  
  logMessage('Backup scheduler running (daily backups at 2:00 AM)');
}

// Handle command line arguments
const args = process.argv.slice(2);

if (args.length === 0) {
  console.log('Usage:');
  console.log('  node automated-backup.js create          - Create a new backup');
  console.log('  node automated-backup.js list            - List available backups');
  console.log('  node automated-backup.js validate <file> - Validate a backup file');
  console.log('  node automated-backup.js schedule        - Start backup scheduler');
  console.log('  node automated-backup.js cleanup         - Clean up old backups');
  process.exit(1);
}

const command = args[0];

switch (command) {
  case 'create':
    createBackup();
    break;
  case 'list':
    listBackups();
    break;
  case 'validate':
    if (args.length < 2) {
      console.error('Please specify a backup file to validate');
      process.exit(1);
    }
    validateBackup(args[1]);
    break;
  case 'schedule':
    scheduleBackups();
    break;
  case 'cleanup':
    cleanupOldBackups();
    break;
  default:
    console.error(`Unknown command: ${command}`);
    process.exit(1);
}